#include "qelib.h"
#include "qe_driver.h"
#include "qe_gpio.h"
#include "libfdt.h"
#include "dtb_blob_data.h"

QELOG_DOMAIN("dm-scan");

extern qe_driver qe_driver_list_start;
extern qe_driver qe_driver_list_end;
static qe_driver *tab_base;
static qe_size tab_size;

static int driver_matched(qe_driver *driver, const char *compatible, int len) 
{
    const qe_device_id *match;

    //qe_debug("driver %s match %s", driver->name, compatible);

    for (match = driver->of_match; match->compatible; match++) {
        //qe_debug("match id %s", match->compatible);
        if (qe_strcmp(compatible, match->compatible) == 0) {
            return 1;
        }
    }

    //qe_debug("not matched");

    return 0;
}

static void fdt_match(const void *fdt, int offset)
{
    int i;
    int len;
    const char *name;
    const char *compatible;
    qe_driver *driver;

    name = fdt_get_name(fdt, offset, &len);

    compatible = fdt_getprop(fdt, offset, "compatible", &len);
    if (!compatible || len <= 0) {
        return;
    }

    qe_debug("%s %s", name, compatible);

    for (i=0; i<tab_size; i++) {

        driver = &tab_base[i];

        if (!driver->of_match)
            continue;

        if (driver_matched(driver, compatible, len)) {
            //qe_info("match dev:%s drv:%s %s", name, driver->name);
            if (driver->probe)
                driver->probe(fdt, offset);
        }
    }
}

static void fdt_scan(const void *fdt, int start)
{
    int ret;
    int offset;

    for (offset = fdt_first_subnode(fdt, start); 
         offset >= 0;
         offset = fdt_next_subnode(fdt, offset)) {
        
        fdt_match(fdt, offset);

        fdt_scan(fdt, offset);
    }
}

int main(int argc, char *argv[])
{
    const void *fdt;
    qe_driver *base;
    
    qelog_init(QELOG_DEBUG, QELOG_CL|QELOG_DM|QELOG_LV);

    qe_debug("ddd");

    fdt = dtb_get_blob_data();
    if (fdt_check_header(fdt) != 0) {
        qe_error("fdt check error");
        return -1;
    }

    base = (qe_driver *)&qe_driver_list_start;
    tab_base = &base[1];
    tab_size = ((qe_size)(&qe_driver_list_end)
                            - (qe_size)(&qe_driver_list_start))
                            / sizeof(qe_driver) - 2;
    qe_debug("start %p %p", &qe_driver_list_start, tab_base);
    qe_debug("end %p", &qe_driver_list_end);
    qe_debug("driver base %p size %d %d", tab_base, tab_size, sizeof(qe_driver));

    // for (int i=0; i<tab_size; i++) {
    //     qe_debug("driver %p", &tab_base[i]);
    //     qe_debug("driver %p %s %s", &tab_base[i], tab_base[i].name, tab_base[i].of_match[0].compatible);
    // }

    qe_debug("fdt valid");

    char data[3];

    qe_hexdump_debug(data, 1);

    fdt_scan(fdt, 0);

    return 0;
}